#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
数据库基础模型定义和Repository基类
"""

import os
import sys
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_, desc, asc, func
from typing import List, Optional, Dict, Any, Union, Type, TypeVar
from abc import ABC, abstractmethod
import math

# 添加项目根目录到路径
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
if project_root not in sys.path:
    sys.path.insert(0, project_root)

from src.common.database import get_session

# 创建基础模型类
Base = declarative_base()

# 常量定义
ROOT_DIRECTORY_ID = 1

# 泛型类型变量
T = TypeVar('T', bound=Base)


class PageResult:
    """分页结果类"""

    def __init__(self, records: List[Any], total: int, page: int, size: int):
        self.records = records  # 当前页数据
        self.total = total      # 总记录数
        self.page = page        # 当前页码（从1开始）
        self.size = size        # 每页大小
        self.pages = math.ceil(total / size) if size > 0 else 0  # 总页数
        self.has_previous = page > 1
        self.has_next = page < self.pages

    def to_dict(self) -> Dict[str, Any]:
        """转换为字典格式"""
        return {
            'records': self.records,
            'total': self.total,
            'page': self.page,
            'size': self.size,
            'pages': self.pages,
            'has_previous': self.has_previous,
            'has_next': self.has_next
        }


class QueryCondition:
    """查询条件构建器"""

    def __init__(self):
        self.conditions = []

    def eq(self, field, value):
        """等于条件"""
        if value is not None:
            self.conditions.append(field == value)
        return self

    def ne(self, field, value):
        """不等于条件"""
        if value is not None:
            self.conditions.append(field != value)
        return self

    def like(self, field, value):
        """模糊查询条件"""
        if value is not None:
            self.conditions.append(field.like(f'%{value}%'))
        return self

    def in_(self, field, values):
        """IN条件"""
        if values and len(values) > 0:
            self.conditions.append(field.in_(values))
        return self

    def not_in(self, field, values):
        """NOT IN条件"""
        if values and len(values) > 0:
            self.conditions.append(~field.in_(values))
        return self

    def gt(self, field, value):
        """大于条件"""
        if value is not None:
            self.conditions.append(field > value)
        return self

    def ge(self, field, value):
        """大于等于条件"""
        if value is not None:
            self.conditions.append(field >= value)
        return self

    def lt(self, field, value):
        """小于条件"""
        if value is not None:
            self.conditions.append(field < value)
        return self

    def le(self, field, value):
        """小于等于条件"""
        if value is not None:
            self.conditions.append(field <= value)
        return self

    def is_null(self, field):
        """IS NULL条件"""
        self.conditions.append(field.is_(None))
        return self

    def is_not_null(self, field):
        """IS NOT NULL条件"""
        self.conditions.append(field.isnot(None))
        return self

    def between(self, field, start, end):
        """BETWEEN条件"""
        if start is not None and end is not None:
            self.conditions.append(field.between(start, end))
        return self

    def and_(self, *conditions):
        """AND条件组合"""
        if conditions:
            self.conditions.append(and_(*conditions))
        return self

    def or_(self, *conditions):
        """OR条件组合"""
        if conditions:
            self.conditions.append(or_(*conditions))
        return self

    def build(self):
        """构建最终的查询条件"""
        if not self.conditions:
            return None
        if len(self.conditions) == 1:
            return self.conditions[0]
        return and_(*self.conditions)


class BaseRepository(ABC):
    """基础Repository类，提供通用的CRUD操作"""

    def __init__(self, model_class: Type[T]):
        """初始化Repository
        
        Args:
            model_class: 模型类
        """
        self.model_class = model_class

    @property
    def session(self) -> Session:
        """获取当前线程的session"""
        return get_session()

    def save(self, entity: T) -> T:
        """保存实体（新增或更新）"""
        try:
            self.session.add(entity)
            self.session.commit()
            self.session.refresh(entity)
            return entity
        except Exception as e:
            self.session.rollback()
            raise e

    def save_batch(self, entities: List[T]) -> List[T]:
        """批量保存实体"""
        try:
            self.session.add_all(entities)
            self.session.commit()
            for entity in entities:
                self.session.refresh(entity)
            return entities
        except Exception as e:
            self.session.rollback()
            raise e

    def delete_by_id(self, entity_id: Union[int, str]) -> bool:
        """根据ID删除实体"""
        try:
            entity = self.get_by_id(entity_id)
            if entity:
                self.session.delete(entity)
                self.session.commit()
                return True
            return False
        except Exception as e:
            self.session.rollback()
            raise e

    def delete(self, entity: T) -> bool:
        """删除实体"""
        try:
            self.session.delete(entity)
            self.session.commit()
            return True
        except Exception as e:
            self.session.rollback()
            raise e

    def delete_batch(self, entities: List[T]) -> bool:
        """批量删除实体"""
        try:
            for entity in entities:
                self.session.delete(entity)
            self.session.commit()
            return True
        except Exception as e:
            self.session.rollback()
            raise e

    def delete_by_condition(self, condition: QueryCondition) -> int:
        """根据条件删除"""
        try:
            query = self.session.query(self.model_class)
            where_clause = condition.build()
            if where_clause is not None:
                query = query.filter(where_clause)
            count = query.count()
            query.delete(synchronize_session=False)
            self.session.commit()
            return count
        except Exception as e:
            self.session.rollback()
            raise e

    def update_by_id(self, entity_id: Union[int, str], **kwargs) -> bool:
        """根据ID更新实体"""
        try:
            entity = self.get_by_id(entity_id)
            if entity:
                for key, value in kwargs.items():
                    if hasattr(entity, key):
                        setattr(entity, key, value)
                self.session.commit()
                return True
            return False
        except Exception as e:
            self.session.rollback()
            raise e

    def update_by_condition(self, condition: QueryCondition, **kwargs) -> int:
        """根据条件批量更新"""
        try:
            query = self.session.query(self.model_class)
            where_clause = condition.build()
            if where_clause is not None:
                query = query.filter(where_clause)
            count = query.count()
            query.update(kwargs, synchronize_session=False)
            self.session.commit()
            return count
        except Exception as e:
            self.session.rollback()
            raise e

    def get_by_id(self, entity_id: Union[int, str]) -> Optional[T]:
        """根据ID查询实体"""
        return self.session.query(self.model_class).filter(
            self.model_class.id == entity_id
        ).first()

    def get_one(self, condition: QueryCondition) -> Optional[T]:
        """根据条件查询单个实体"""
        query = self.session.query(self.model_class)
        where_clause = condition.build()
        if where_clause is not None:
            query = query.filter(where_clause)
        return query.first()

    def exists(self, condition: QueryCondition) -> bool:
        """检查是否存在满足条件的记录"""
        query = self.session.query(self.model_class)
        where_clause = condition.build()
        if where_clause is not None:
            query = query.filter(where_clause)
        return query.first() is not None

    def count(self, condition: Optional[QueryCondition] = None) -> int:
        """统计记录数"""
        query = self.session.query(func.count(self.model_class.id))
        if condition:
            where_clause = condition.build()
            if where_clause is not None:
                query = query.filter(where_clause)
        return query.scalar()

    def list_all(self) -> List[T]:
        """查询所有记录"""
        return self.session.query(self.model_class).all()

    def list_by_condition(self, condition: Optional[QueryCondition] = None,
                         order_by: Optional[str] = None,
                         desc_order: bool = False) -> List[T]:
        """根据条件查询列表"""
        query = self.session.query(self.model_class)

        # 添加查询条件
        if condition:
            where_clause = condition.build()
            if where_clause is not None:
                query = query.filter(where_clause)

        # 添加排序
        if order_by and hasattr(self.model_class, order_by):
            field = getattr(self.model_class, order_by)
            if desc_order:
                query = query.order_by(desc(field))
            else:
                query = query.order_by(asc(field))

        return query.all()

    def page(self, page: int = 1, size: int = 10,
             condition: Optional[QueryCondition] = None,
             order_by: Optional[str] = None,
             desc_order: bool = False) -> PageResult:
        """分页查询"""
        if page < 1:
            page = 1
        if size < 1:
            size = 10

        query = self.session.query(self.model_class)

        # 添加查询条件
        if condition:
            where_clause = condition.build()
            if where_clause is not None:
                query = query.filter(where_clause)

        # 统计总数
        total = query.count()

        # 添加排序
        if order_by and hasattr(self.model_class, order_by):
            field = getattr(self.model_class, order_by)
            if desc_order:
                query = query.order_by(desc(field))
            else:
                query = query.order_by(asc(field))

        # 分页
        offset = (page - 1) * size
        records = query.offset(offset).limit(size).all()

        return PageResult(records, total, page, size)

    def list_by_ids(self, ids: List[Union[int, str]]) -> List[T]:
        """根据ID列表查询"""
        if not ids:
            return []
        return self.session.query(self.model_class).filter(
            self.model_class.id.in_(ids)
        ).all()

    def get_session(self) -> Session:
        """获取数据库会话"""
        return self.session